﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.IO;

namespace Calcite.Classes.Misc
{
    /// <summary>
    /// Use to store the coordinates of a cell
    /// </summary>
    class CellCoords
    {
        public int Column;
        public int Row;

        public CellCoords(int row, int column)
        {
            this.Column = column;
            this.Row = row;
        }
    }

    /// <summary>
    /// Contains miscelleneous/generic functions
    /// </summary>
    class Functions
    {
        /// <summary>
        /// Returns a list of all Controls buried in the passed control
        /// </summary>
        /// <param name="topControl"></param>
        /// <returns></returns>
        internal static List<Control> GetAllChildControls(Control topControl)
        {
            // Walk all the child controls and return them in a list
            List<Control> ctrlStore = new List<Control>();
            ctrlStore.Add(topControl);
            if (topControl.HasChildren)
            {
                foreach (Control ctrl in topControl.Controls)
                {
                    ctrlStore.AddRange(GetAllChildControls(ctrl));
                }
            }
            return ctrlStore;
        }

        /// <summary>
        /// Return the list of integers specified by the range string.  Default uses '-' as range operator 
        /// and comma or space to separate clauses. 
        /// i.e. 1-3,5,7,10-12 would give 1,2,3,5,7,10,11,12
        /// Spaces are ignored, invalid syntax is ignored
        /// </summary>
        /// <param name="rangeFormat">Range format string</param>
        /// <returns></returns>
        internal static List<int> ParseRangeFormat(string rangeFormat)
        {
            // If clause and range separator not specified, use comma or space and hyphen
            return ParseRangeFormat(rangeFormat, new string[]{",", " "}, new string[]{"-"});
        }

        /// <summary>
        /// Return the list of integers specified by the range string.  Default uses '-' as range operator 
        /// and comma to separate clauses. 
        /// i.e. 1-3,5,7,10-12 would give 1,2,3,5,7,10,11,12
        /// Spaces are ignored, invalid syntax is ignored 
        /// </summary>
        /// <param name="rangeFormat">Range format string</param>
        /// <param name="clauseSeparator">Default is ","</param>
        /// <param name="rangeSeparator">Default is "-"</param>
        /// <returns></returns>
        internal static List<int> ParseRangeFormat(string rangeFormat, string[] clauseSeparators, string[] rangeSeparators)
        {
            // Format can be a range 1-5 or separate integers, separated by commas
            List<int> intsInRange = new List<int>();
            int result, lower, upper, i;
            foreach (string clause in rangeFormat.Split(clauseSeparators, StringSplitOptions.RemoveEmptyEntries))
            {
                string[] nums = clause.Split(rangeSeparators, StringSplitOptions.RemoveEmptyEntries);
                // Trim off any whitespace
                Array.ForEach<string>(nums, x => x.Trim());
                if (nums.Length == 1)
                {
                    if (Int32.TryParse(nums[0], out result))
                    {
                        intsInRange.Add(result);
                    }
                }
                else if (nums.Length == 2)
                {
                    if (Int32.TryParse(nums[0], out lower) 
                        && Int32.TryParse(nums[1], out upper)
                        && upper >= lower)
                    {
                        for (i = lower; i <= upper; i++)
                        {
                            intsInRange.Add(i);
                        }
                    }
                }
            }
            return intsInRange.Distinct().ToList<int>();
        }

        /// <summary>
        /// Populate a DataGridViewRow with parameters in a list. Items in list beyond 
        /// number of cells in Row are ignored, if list is short then cells are given default values (empty string)
        /// </summary>
        /// <param name="row"></param>
        /// <param name="strList"></param>
        internal static void FillDataGridViewRow(DataGridViewRow row, List<string> strList)
        {
            // May overload later with other types
            // Take the datagridviewrow as the limiting factor
            int i;
            for (i = 0; i < row.Cells.Count; i++)
            {
                if (i < strList.Count)
                {
                    row.Cells[i].Value = strList[i];
                }
                else
                {
                    row.Cells[i].Value = String.Empty;
                }
            }
        }

        /// <summary>
        /// Build a list caching the values of the DataGridViewRow passed
        /// </summary>
        /// <param name="row"></param>
        /// <param name="strList"></param>
        internal static List<string> CacheDataGridViewRow(DataGridViewRow row)
        {
            // May overload later with other types
            List<string> strList = new List<string>();
            strList.Clear();
            int i;
            for (i = 0; i < row.Cells.Count; i++)
            {
                if (row.Cells[i].Value == null)
                {
                    strList.Add(String.Empty);
                }
                else
                {
                    strList.Add(row.Cells[i].Value.ToString());
                }
            }
            return strList;
        }
        //        If you implement the following logic:
        //read the first 1000 bytes file
        //if number of <LF> > 5 and
        //number of <NUL> == 0 and
        //frequency of ' '..'~' > 90%
        //then
        //return text
        //else
        //return binary
        //end if

        ///// <summary>
        ///// Taken from http://stackoverflow.com/questions/58510 to determin file type
        ///// // TODO: Replace this with a Mono friendly option
        ///// </summary>
        ///// <param name="pBC"></param>
        ///// <param name="pwzUrl"></param>
        ///// <param name="pBuffer"></param>
        ///// <param name="cbSize"></param>
        ///// <param name="pwzMimeProposed"></param>
        ///// <param name="dwMimeFlags"></param>
        ///// <param name="ppwzMimeOut"></param>
        ///// <param name="dwReserverd"></param>
        ///// <returns></returns>
        //[DllImport(@"urlmon.dll", CharSet = CharSet.Auto)]
        //private extern static System.UInt32 FindMimeFromData(
        //    System.UInt32 pBC,
        //    [MarshalAs(UnmanagedType.LPStr)] System.String pwzUrl,
        //    [MarshalAs(UnmanagedType.LPArray)] byte[] pBuffer,
        //    System.UInt32 cbSize,
        //    [MarshalAs(UnmanagedType.LPStr)] System.String pwzMimeProposed,
        //    System.UInt32 dwMimeFlags,
        //    out System.UInt32 ppwzMimeOut,
        //    System.UInt32 dwReserverd
        //);

        //internal static string GetMimeFromFile(string filename)

        //{
        //    if (!File.Exists(filename))
        //        throw new FileNotFoundException(filename + " not found");

        //    byte[] buffer = new byte[256];
        //    using (FileStream fs = new FileStream(filename, FileMode.Open))
        //    {
        //        if (fs.Length >= 256)
        //            fs.Read(buffer, 0, 256);
        //        else
        //            fs.Read(buffer, 0, (int)fs.Length);
        //    }
        //    try
        //    {
        //        System.UInt32 mimetype;
        //        FindMimeFromData(0, null, buffer, 256, null, 0, out mimetype, 0);
        //        System.IntPtr mimeTypePtr = new IntPtr(mimetype);
        //        string mime = Marshal.PtrToStringUni(mimeTypePtr);
        //        Marshal.FreeCoTaskMem(mimeTypePtr);
        //        return mime;
        //    }
        //    catch (Exception e)
        //    {
        //        return "unknown/unknown";
        //    }
        //}


    }

}
